Python
Scope: This document defines the mandatory standards for all Python code to ensure readability, maintainability, security, and performance.
1. Code Layout & Formatting
1.1 Indentation
- Rule: Use 4 spaces per indentation level.
- Prohibited: Never use tabs.
1.2 Line Length
- Standard: Limit all lines to a maximum of 79 characters (PEP 8 standard).
- Modern Exception: For complex configurations or type hints, 88 characters (Black formatter default) is acceptable if agreed upon by the team.
- Handling: Break long lines using parentheses
(), not backslashes\.
# Good user_permissions = ( "read_access", "write_access", "delete_access", "admin_access" )
1.3 Imports
- Order:
- Standard Library (e.g.,
os,sys) - Third-Party (e.g.,
requests,pandas) - Local Application (e.g.,
from myapp.utils import helper)
- Standard Library (e.g.,
- Style: Use absolute imports. Avoid wildcard imports (
from module import *).
1.4 Whitespace
- Operators: Surround binary operators with a single space (
x = 12). - Definitions: One space after the colon in type hints (
age: int). - Functions: Two blank lines before top-level functions; one blank line before methods inside a class.
2. Naming Conventions
Follow strict PEP 8 naming to communicate intent instantly.
| Entity | Convention | Example |
|---|---|---|
| Modules | snake_case |
data_processor.py |
| Classes | PascalCase |
UserProfile |
| Functions | snake_case |
calculate_total() |
| Variables | snake_case |
is_active, user_id |
| Constants | SCREAMING_SNAKE |
MAX_RETRIES = 3 |
| Private | _leading_underscore |
_internal_cache |
3. Modern Type Hinting (Python 3.10+)
Type hinting is no longer optional; it is mandatory for maintainability.
3.1 Syntax
- Rule: Use the modern pipe | operator for Unions instead of importing
UnionorOptional. - Return Types: Always specify the return type, even if it is
None.
# Bad (Old Style) from typing import List, Optional def find_user(ids: List[int]) -> Optional[str]: ... # Good (Modern Style) def find_user(ids: list[int]) -> str | None: ...
3.2 Collections
- Rule: Use standard collections
(list, dict, tuple)instead oftyping.Listortyping.Dict.
4. Documentation & Docstrings
4.1 Format
- Standard: Use the Google Style docstring format. It is cleaner and more readable than reStructuredText.
- Requirement: All public modules, classes, and functions must have a docstring.
def connect_to_db(timeout: int = 10) -> bool: """Establishes a connection to the primary database. Args: timeout (int): Max time in seconds to wait for connection. Returns: bool: True if connection successful, False otherwise. Raises: ConnectionError: If the network is down. """ pass
4.2 Comments
- Rule: Comments must explain "Why", not "What".
- Maintenance: Delete commented-out code immediately. Do not commit dead code.
5. Programming Best Practices
5.1 Error Handling
- Prohibited: Never use bare except:.
- Best Practice: Catch specific exceptions.
- Chaining: When re-raising an exception, use
raise ... from eto preserve the stack trace.
# Good try: process_data() except ValueError as e: raise DataProcessingError("Invalid data format") from e
5.2 Conditionals & Truthiness
- Explicit is better: Use
if x is None:insteadof if x == None:. - Implicit False: Use implicit boolean checks for lists/strings.
- Yes:
if my_list:(Checks if list is not empty) - No:
if len(my_list) > 0:
5.3 Magic Numbers
- Rule: Replace raw numbers/strings with named constants or Enums.
from enum import Enum class Status(Enum): PENDING = "pending" ACTIVE = "active" # Usage if user.status == Status.ACTIVE: ...
6. Async & Performance (Modern Standards)
6.1 Async/Await
- Rule: Do not use blocking code (e.g.,
time.sleep, requests.get) insideasyncfunctions. Useawait asyncio.sleepor asynchronous libraries (e.g.,httpx). - Safe Handling: Use
TaskGroup(Python 3.11+) for managing concurrent tasks safely.
6.2 Loops
- Rule: Use
enumerate()for indexing. - Rule: Prefer List Comprehensions for simple transformations, but use
forloops if the logic is complex.
7. Security & Privacy
- Secrets: Never commit API keys, passwords, or tokens to Git. Use
.envfiles andpydantic-settings. - Inputs: Always validate user input. Never pass user input directly to
eval(), exec(),or raw SQL queries (use ORM or parameterized queries).
8. Automation & Tooling
Manual enforcement is unreliable. The project can use the following automated tools:
- Ruff: The modern, high-speed replacement for Flake8 and isort.
- Black: For uncompromising code formatting.
- Mypy: For static type checking.
- Pre-commit: To run these checks before every commit.
Configuration (pyproject.toml)
Copy this configuration to standardise your team's tooling:
[tool.ruff] line-length = 79 select = ["E", "F", "I", "UP", "B"] # Enforce PEP8, Imports, pyupgrade, Bugbear [tool.mypy] strict = true ignore_missing_imports = true
Recommended folder structure for modern Python projects)
project_root/ │ ├── src/ │ └── my_package/ │ ├── __init__.py │ ├── main.py │ └── utils.py ├── tests/ │ ├── __init__.py │ └── test_main.py ├── .env # Secrets (GitIgnored) ├── .gitignore ├── pyproject.toml # Tooling Config └── README.md